package com.baymax.test.scene.demo

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.collection.arraySetOf
import com.baymax.test.scene.BaseScene
import com.baymax.test.scene.ILogger
import com.baymax.test.scene.addButton
import com.baymax.test.scene.installLogger
import com.baymax.test.scene.newSceneFlexContainer
import com.qiniu.android.dns.DnsManager
import com.qiniu.android.dns.Domain
import com.qiniu.android.dns.IResolver
import com.qiniu.android.dns.dns.DnsUdpResolver
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import okhttp3.Dns
import okio.Buffer
import okio.BufferedSource
import okio.buffer
import okio.sink
import okio.source
import okio.use
import org.koin.core.component.KoinComponent
import java.net.InetAddress
import kotlin.time.measureTimedValue


class DNSDemo : BaseScene() {
    lateinit var logger: ILogger

    override fun onCreateView(p0: LayoutInflater, p1: ViewGroup, p2: Bundle?): View {
        return p1.newSceneFlexContainer {
            logger = installLogger(this)

            addButton("dns") {
                val r1 = testDNS("baidu.com")
                val r2 = testDNS("example.com")
                val r3 = testDNS("tvlookbackpanel-ystzw.zjmobile.wasu.tv")
                val fos by lazy { requireActivity().openFileOutput("dns", Context.MODE_APPEND) }
                launch(Dispatchers.IO) {
                    val buffer = Buffer()
                    r1.await().onSuccess { it.writeBuffer(buffer) }
                    r2.await().onSuccess { it.writeBuffer(buffer) }
                    r3.await().onSuccess { it.writeBuffer(buffer) }
                    fos.sink().buffer().use {
                        it.writeAll(buffer)
                    }
                }
            }

            addButton("read") {
                val input =
                    kotlin.runCatching { requireActivity().openFileInput("dns") }.getOrNull()
                        ?: return@addButton
                val v = measureTimedValue {
                    val l = arraySetOf<DNSResult>()
                    input.source().buffer().use {
                        while (!it.exhausted()) {
                            try {
                                val dns = it.dns()
                                l.add(dns)
                            } catch (e: Exception) {
                                e.printStackTrace()
                            }
                        }
                    }
                    l
                }
                println(v)
            }
        }


    }

    override fun onDestroyView() {
        super.onDestroyView()
    }


    fun BufferedSource.dns(): DNSResult {
        val nameL = this.readInt()
        val name = this.readUtf8(nameL.toLong())
        val s = this.readInt()
        if (s > 0) {
            val add = (0 until s).mapNotNull {
                val ipl = this.readByte().toInt()
                if (ipl > 0) {
                    InetAddress.getByAddress(this.readByteArray(ipl.toLong()))
                } else null
            }
            return DNSResult(name, add)
        }
        return DNSResult(name, emptyList())
    }

    data class DNSResult(val name: String, val result: List<InetAddress>) {
        fun writeBuffer(buffer: Buffer) {
            buffer.writeInt(name.length)
            buffer.writeUtf8(name)
            buffer.writeInt(result.size)
            result.onEach { add ->
                if (add.address != null) {
                    buffer.writeByte(add.address.size)
                    add.address.onEach { buffer.writeByte(it.toInt()) }
                } else {
                    buffer.writeByte(0)
                }
            }
        }

    }

    fun testDNS(host: String): Deferred<Result<DNSResult>> {
        return async(Dispatchers.IO) {
            runCatching {
                println("testDNS $host start !")
                val d = measureTimedValue {
                    Happy.lookup(host)
                }
                logger(
                    "testDNS $host ,${d.value.joinToString(transform = { it.hostAddress.orEmpty() })} " +
                            "time cost ${d.duration}"
                )
                DNSResult(host, d.value)

            }.onFailure {
                logger("testDNS $host onError fail ")
                it.printStackTrace()
            }
        }

    }

    object Happy : Dns, KoinComponent {

        val dns: DnsManager by lazy {
            val resolvers: Array<IResolver> = arrayOf(
//                AndroidDnsServer.defaultResolver(get()), //系统默认 DNS 服务器 ,
                DnsUdpResolver("8.8.8.8"),//自定义 DNS 服务器地址
//                DohResolver("https://dns.alidns.com/dns-query"),
            )
            DnsManager(null, resolvers)
        }


        override fun lookup(hostname: String): List<InetAddress> {
            return dns.queryInetAdress(Domain(hostname)).toList()
        }
    }

}